#include "Cell.h"

Cell::Cell(float x, float y, float deltaX, float deltaY) {
	initializeCell(x,y,deltaX,deltaY);
};

Cell::Cell(float x, float y, float delta) {
	initializeCell(x,y,delta,delta);
};

void Cell::initializeCell(float x, float y, float deltaX, float deltaY) {
		
	ll = new Point(x,y);
	ul = new Point(x,y + deltaY);
	ur = new Point(x+deltaX,y+deltaY);
	lr = new Point(x+deltaX,y);
	
	splitTop = -1;
	splitRight = -1;
	splitBottom = -1;
	splitLeft = -1;

	checkForSplit();

	doRecursiveSplit();
}

void Cell::doRecursiveSplit() {
	
	float deltaX = 0;
	float deltaY = 0;
	gX = 0;
	gY = 0;

	if ( (splitTop == 1 || splitBottom == 1) && ( splitLeft == 1 || splitRight == 1 ) ) {
		gX = 2;
		gY = 2;
		deltaX = fabs( lr->x - ll->x ) / (float)2;
		deltaY = fabs( ul->y - ll->y ) / (float)2;
	} else if (splitTop == 1 || splitBottom == 1) {
		gX = 2;
		gY = 1;
		deltaX = fabs( lr->x - ll->x ) / (float)2;
		deltaY = fabs( ul->y - ll->y );
	} else if ( splitLeft == 1 || splitRight == 1 ) {
		gX = 1;
		gY = 2;
		deltaX = fabs( lr->x - ll->x );
		deltaY = fabs( ul->y - ll->y ) / (float)2;
	}

	if (gX != 0 && gY != 0) {

		children.resize(gX);
		for (int i = 0; i < children.size(); i++) {
			children[i].resize(gY);
		}

		float xValue = ll->x;
		float yValue = ll->y;

		for (int x = 0; x < gX; x++) {

			for (int y = 0; y < gY; y++) {

				children[x][y] = new Cell(xValue, yValue, deltaX, deltaY);

				yValue += deltaY;
			}
			yValue = ll->y;
			xValue += deltaX;
		}
	}
};

int Cell::toBeSplit(Point* p1, Point* p2) {
	Point* realMiddle = getMiddlePoint(p1, p2);

	float approximatedMiddle = functionApproximatedValue(p1, p2, realMiddle);

	if (realMiddle->z - approximatedMiddle > Variables::threshold)
		return 1;
	else
		return 0;
};

void Cell::checkForSplit() {
	
	splitTop  = toBeSplit(ul, ur);
	splitRight = toBeSplit(ur, lr);
	splitBottom = toBeSplit(lr, ll);
	splitLeft = toBeSplit(ll, ul);
	
};
float Cell::functionApproximatedValue(Point* p1, Point* p2, Point* middle) {
	float x1 = p1->x;
	float y1 = p1->y;
	float z1 = p1->z;

	float x2 = p2->x;
	float y2 = p2->y;
	float z2 = p2->z;

	float z = -1;

	if (x1 == x2) {
		z = z1 + (((middle->y-y1)*(z2-z1))/(y2-y1));
	}
	if (y1 == y2) {
		z = z1 + (((middle->x-x1)*(z2-z1))/(x2-x1));	
	}

	return z;
	
};
Point* Cell::getMiddlePoint(Point* p1, Point* p2) {
	float x = (p1->x + p2->x) / 2;
	float y = (p1->y + p2->y) / 2;
	Point* middle = new Point(x,y);

	return middle;
};

ostream& operator<<(ostream& os,Cell* c) {
	os << c->ll;
	os << c->ul;
	os << c->ur;
	os << c->lr;

	for (int x = 0; x < c->gX; x++) {

		for (int y = 0; y < c->gY; y++) {

			os << c->children[x][y];
						
		}

	}
}